﻿using System;
using System.IO;
using System.Net.Sockets;
using System.Security.Cryptography;

namespace 网络加密流实现
{
    public class TLSStream : Stream
    {
        RijndaelManaged rDel;
        protected Stream EncryptionStream;
        public TLSStream(Socket sock) : this(new NetworkStream(sock)) { }
        public TLSStream(NetworkStream stream) : base()
        {
            rDel = new RijndaelManaged
            {
                Key = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 },
                IV = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
                Mode = CipherMode.CBC,
                Padding = PaddingMode.PKCS7
            };
            EncryptionStream = stream;
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            byte[] byr = new byte[count % 16 == 0 ? count + 16 : count + (16 - count % 16)];
            int s = EncryptionStream.Read(byr, 0, byr.Length);
            while (s < byr.Length)
            {
                s += EncryptionStream.Read(byr, s, byr.Length - s);
            }
            ICryptoTransform cTransform = rDel.CreateDecryptor();
            byte[] data_dec = cTransform.TransformFinalBlock(byr, 0, byr.Length);
            Array.Copy(data_dec, 0, buffer, offset, count);
            return data_dec.Length;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            ICryptoTransform cTransform = rDel.CreateEncryptor();
            byte[] data = cTransform.TransformFinalBlock(buffer, offset, count);
            EncryptionStream.Write(data, 0, data.Length);
        }


        #region 流重写
        public override bool CanRead => EncryptionStream.CanRead;
        public override bool CanSeek => EncryptionStream.CanSeek;
        public override bool CanWrite => EncryptionStream.CanWrite;
        public override void Flush() => EncryptionStream.Flush();
        public override long Length => EncryptionStream.Length;
        public override long Position { get { return EncryptionStream.Position; } set { EncryptionStream.Position = value; } }
        public override long Seek(long offset, SeekOrigin origin) => EncryptionStream.Seek(offset, origin);
        public override void SetLength(long value) => EncryptionStream.SetLength(value);
        #endregion
        #region 释放
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                rDel.Dispose();
            }
        }
        #endregion
    }
}
